<template>
  <div class="number-input-container">
    <!-- 标签 -->
    <label v-if="label" :for="inputId" class="block text-sm font-medium text-text-primary mb-2">
      {{ label }}
      <span v-if="required" class="text-red-500 ml-1 font-bold">*</span>
    </label>
    
    <!-- 数字输入控件 -->
    <div class="relative flex items-center w-full">
      <!-- 减少按钮 -->
      <button
        type="button"
        :disabled="disabled || loading || isMinValue"
        @click="decrement"
        @mousedown="handleDecrementMouseDown"
        @mouseup="handleMouseUp"
        @mouseleave="handleMouseLeave"
        class="number-input-button number-input-button-left"
        :class="decrementButtonClasses"
      >
        <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4"></path>
        </svg>
      </button>
      
      <!-- 输入框 -->
      <input
        :id="inputId"
        ref="inputRef"
        v-model="displayValue"
        type="number"
        :min="min"
        :max="max"
        :step="step"
        :placeholder="placeholder"
        :disabled="disabled"
        :required="required"
        @input="handleInput"
        @blur="handleBlur"
        @focus="handleFocus"
        @keydown="handleKeydown"
        class="number-input-field"
        :class="inputClasses"
      />
      
      <!-- 增加按钮 -->
      <button
        type="button"
        :disabled="disabled || loading || isMaxValue"
        @click="increment"
        @mousedown="handleIncrementMouseDown"
        @mouseup="handleMouseUp"
        @mouseleave="handleMouseLeave"
        class="number-input-button number-input-button-right"
        :class="incrementButtonClasses"
      >
        <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
        </svg>
      </button>
    </div>
    
    <!-- 错误信息 -->
    <p v-if="error" class="mt-1 text-sm text-error">{{ error }}</p>
    
    <!-- 步长验证警告 -->
    <p v-else-if="!isValidStepValue" class="mt-1 text-sm text-yellow-500">
      值不符合步长要求，已自动调整
    </p>
    
    <!-- 帮助文本 -->
    <p v-else-if="helpText" class="mt-1 text-sm text-text-secondary">{{ helpText }}</p>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch, nextTick } from 'vue'

interface Props {
  modelValue?: number
  label?: string
  placeholder?: string
  min?: number
  max?: number
  step?: number
  disabled?: boolean
  loading?: boolean
  required?: boolean
  error?: string
  helpText?: string
  size?: 'sm' | 'md' | 'lg'
  variant?: 'primary' | 'secondary' | 'outline'
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: undefined,
  placeholder: '请输入数字',
  min: -Infinity,
  max: Infinity,
  step: 1,
  disabled: false,
  loading: false,
  required: false,
  size: 'md',
  variant: 'outline'
})

const emit = defineEmits<{
  'update:modelValue': [value: number]
  'change': [value: number]
  'blur': [event: FocusEvent]
  'focus': [event: FocusEvent]
}>()

// 响应式数据
const inputRef = ref<HTMLInputElement>()
const displayValue = ref('')
const isActive = ref(false)
const isFocused = ref(false)
const isDecrementActive = ref(false)
const isIncrementActive = ref(false)

// 生成唯一ID
const inputId = computed(() => `number-input-${Math.random().toString(36).substr(2, 9)}`)

// 计算属性
const isMinValue = computed(() => {
  if (props.modelValue === undefined) return false
  // 使用精确比较，避免浮点数精度问题
  if (props.step !== 1 && props.step < 1) {
    const stepPrecision = props.step.toString().split('.')[1]?.length || 0
    const multiplier = Math.pow(10, stepPrecision)
    return Math.round(props.modelValue * multiplier) <= Math.round(props.min * multiplier)
  }
  return props.modelValue <= props.min
})

const isMaxValue = computed(() => {
  if (props.modelValue === undefined) return false
  // 使用精确比较，避免浮点数精度问题
  if (props.step !== 1 && props.step < 1) {
    const stepPrecision = props.step.toString().split('.')[1]?.length || 0
    const multiplier = Math.pow(10, stepPrecision)
    return Math.round(props.modelValue * multiplier) >= Math.round(props.max * multiplier)
  }
  return props.modelValue >= props.max
})

// 验证当前值是否符合步长要求
const isValidStepValue = computed(() => {
  if (props.modelValue === undefined || props.step === 1) return true
  if (props.step < 1) {
    const stepPrecision = props.step.toString().split('.')[1]?.length || 0
    const multiplier = Math.pow(10, stepPrecision)
    const roundedValue = Math.round(props.modelValue * multiplier) / multiplier
    return Math.abs(roundedValue - props.modelValue) < 0.001
  }
  return true
})

// 按钮样式类
const baseButtonClasses = computed(() => [
  'flex items-center justify-center font-medium transition-colors duration-200 ease-out disabled:opacity-50 disabled:cursor-not-allowed select-none border border-background-600',
  'focus:outline-none focus:ring-1 focus:ring-primary-500 focus:ring-inset'
])

const decrementButtonClasses = computed(() => {
  const sizeClasses = {
    sm: 'w-7 h-7 text-xs',
    md: 'w-9 h-9 text-sm',
    lg: 'w-11 h-11 text-base'
  }
  
  const variantClasses = {
    primary: `text-white border-primary-600 ${
      isDecrementActive.value 
        ? 'bg-primary-700' 
        : 'bg-primary-600 hover:bg-primary-700'
    }`,
    secondary: `text-text-primary border-background-600 ${
      isDecrementActive.value 
        ? 'bg-background-600' 
        : 'bg-background-700 hover:bg-background-600'
    }`,
    outline: `border-background-600 bg-background-800 text-text-primary ${
      isDecrementActive.value 
        ? 'bg-background-600 text-text-primary' 
        : 'hover:bg-background-700 hover:text-text-primary'
    }`
  }
  
  return [
    ...baseButtonClasses.value,
    sizeClasses[props.size],
    'rounded-l-lg border-r-0 -mr-px',
    variantClasses[props.variant]
  ].join(' ')
})

const incrementButtonClasses = computed(() => {
  const sizeClasses = {
    sm: 'w-7 h-7 text-xs',
    md: 'w-9 h-9 text-sm',
    lg: 'w-11 h-11 text-base'
  }
  
  const variantClasses = {
    primary: `text-white border-primary-600 ${
      isIncrementActive.value 
        ? 'bg-primary-700' 
        : 'bg-primary-600 hover:bg-primary-700'
    }`,
    secondary: `text-text-primary border-background-600 ${
      isIncrementActive.value 
        ? 'bg-background-600' 
        : 'bg-background-700 hover:bg-background-600'
    }`,
    outline: `border-background-600 bg-background-800 text-text-primary ${
      isIncrementActive.value 
        ? 'bg-background-600 text-text-primary' 
        : 'hover:bg-background-700 hover:text-text-primary'
    }`
  }
  
  return [
    ...baseButtonClasses.value,
    sizeClasses[props.size],
    'rounded-r-lg border-l-0 -ml-px',
    variantClasses[props.variant]
  ].join(' ')
})

// 输入框样式类
const inputClasses = computed(() => {
  const sizeClasses = {
    sm: 'px-2 py-1 text-sm',
    md: 'px-3 py-2 text-sm',
    lg: 'px-4 py-2.5 text-base'
  }
  
  const variantClasses = {
    primary: `border-primary-600 bg-primary-50 text-primary-900 placeholder-primary-400 focus:border-primary-500 focus:ring-primary-500`,
    secondary: `border-background-600 bg-background-800 text-text-primary placeholder-text-secondary focus:border-background-500 focus:ring-background-500`,
    outline: `border-background-600 bg-background-900 text-text-primary placeholder-text-secondary focus:border-primary-500 focus:ring-primary-500`
  }
  
  return [
    'flex-1 text-center border border-background-600 bg-background-900 text-text-primary placeholder-text-secondary rounded-none',
    'focus:outline-none focus:ring-1 focus:ring-primary-500 focus:ring-inset',
    'disabled:opacity-50 disabled:cursor-not-allowed',
    sizeClasses[props.size],
    variantClasses[props.variant]
  ].join(' ')
})

// 监听modelValue变化
watch(() => props.modelValue, (newValue) => {
  if (newValue === undefined) {
    displayValue.value = ''
  } else {
    // 如果步长是小数，确保显示的值符合步长精度
    if (props.step !== 1 && props.step < 1) {
      const stepPrecision = props.step.toString().split('.')[1]?.length || 0
      const roundedValue = Math.round(newValue * Math.pow(10, stepPrecision)) / Math.pow(10, stepPrecision)
      displayValue.value = roundedValue.toString()
    } else {
      displayValue.value = newValue.toString()
    }
  }
}, { immediate: true })

// 辅助函数：精确的小数运算
const preciseAdd = (a: number, b: number): number => {
  const precision = Math.max(
    a.toString().split('.')[1]?.length || 0,
    b.toString().split('.')[1]?.length || 0
  )
  const multiplier = Math.pow(10, precision)
  return Math.round((a * multiplier + b * multiplier)) / multiplier
}

const preciseSubtract = (a: number, b: number): number => {
  const precision = Math.max(
    a.toString().split('.')[1]?.length || 0,
    b.toString().split('.')[1]?.length || 0
  )
  const multiplier = Math.pow(10, precision)
  return Math.round((a * multiplier - b * multiplier)) / multiplier
}

// 方法
const updateValue = (value: number) => {
  emit('update:modelValue', value)
  emit('change', value)
}

const increment = () => {
  if (props.disabled || props.loading || isMaxValue.value) return
  
  const currentValue = props.modelValue || 0
  const newValue = Math.min(preciseAdd(currentValue, props.step), props.max)
  updateValue(newValue)
}

const decrement = () => {
  if (props.disabled || props.loading || isMinValue.value) return
  
  const currentValue = props.modelValue || 0
  const newValue = Math.max(preciseSubtract(currentValue, props.step), props.min)
  updateValue(newValue)
}

const handleInput = (event: Event) => {
  const target = event.target as HTMLInputElement
  const value = target.value
  
  if (value === '') {
    // 如果输入为空，不更新值，保持当前值
    return
  } else {
    const numValue = parseFloat(value)
    if (!isNaN(numValue)) {
      // 使用精确的数值处理，避免浮点数精度问题
      const clampedValue = Math.max(props.min, Math.min(numValue, props.max))
      // 如果步长是小数，确保值符合步长要求
      if (props.step !== 1 && props.step < 1) {
        const stepPrecision = props.step.toString().split('.')[1]?.length || 0
        const roundedValue = Math.round(clampedValue * Math.pow(10, stepPrecision)) / Math.pow(10, stepPrecision)
        // 验证值是否符合步长要求
        const isValidStep = Math.abs(roundedValue - clampedValue) < props.step / 2
        if (isValidStep) {
          updateValue(roundedValue)
        } else {
          // 如果不符合步长要求，恢复到上一个有效值
          displayValue.value = (props.modelValue || 0).toString()
        }
      } else {
        updateValue(clampedValue)
      }
    }
  }
}

const handleBlur = (event: FocusEvent) => {
  isFocused.value = false
  
  // 在失去焦点时，确保值符合步长要求
  if (props.step !== 1 && props.step < 1 && props.modelValue !== undefined) {
    const stepPrecision = props.step.toString().split('.')[1]?.length || 0
    const roundedValue = Math.round(props.modelValue * Math.pow(10, stepPrecision)) / Math.pow(10, stepPrecision)
    if (Math.abs(roundedValue - props.modelValue) > 0.001) {
      updateValue(roundedValue)
    }
  }
  
  emit('blur', event)
}

const handleFocus = (event: FocusEvent) => {
  isFocused.value = true
  emit('focus', event)
}

const handleKeydown = (event: KeyboardEvent) => {
  if (event.key === 'ArrowUp') {
    event.preventDefault()
    increment()
  } else if (event.key === 'ArrowDown') {
    event.preventDefault()
    decrement()
  }
}

const handleDecrementMouseDown = () => {
  if (!props.disabled && !props.loading) {
    isDecrementActive.value = true
  }
}

const handleIncrementMouseDown = () => {
  if (!props.disabled && !props.loading) {
    isIncrementActive.value = true
  }
}

const handleMouseUp = () => {
  isDecrementActive.value = false
  isIncrementActive.value = false
}

const handleMouseLeave = () => {
  isDecrementActive.value = false
  isIncrementActive.value = false
}

// 暴露方法
defineExpose({
  focus: () => inputRef.value?.focus(),
  blur: () => inputRef.value?.blur(),
  select: () => inputRef.value?.select()
})
</script>

<style scoped>
.number-input-container {
  @apply w-full;
}

.number-input-field {
  @apply appearance-none;
}

.number-input-field::-webkit-outer-spin-button,
.number-input-field::-webkit-inner-spin-button {
  @apply appearance-none;
  margin: 0;
}

.number-input-field[type=number] {
  -moz-appearance: textfield;
}
</style>
